package com.ashlikun.zxing

import android.graphics.Rect
import androidx.annotation.FloatRange
import com.google.zxing.DecodeHintType
import kotlin.math.min

/**
 * 解码配置：主要用于在扫码识别时，提供一些配置，便于扩展。通过配置可决定内置分析器的能力，从而间接的控制并简化扫码识别的流程
 *
 * >
 * 设置解码 [.setHints]内置的一些解码可参见如下：
 *
 *
 * [DecodeFormatManager.DEFAULT_HINTS]
 * [DecodeFormatManager.ALL_HINTS]
 * [DecodeFormatManager.CODE_128_HINTS]
 * [DecodeFormatManager.QR_CODE_HINTS]
 * [DecodeFormatManager.ONE_DIMENSIONAL_HINTS]
 * [DecodeFormatManager.TWO_DIMENSIONAL_HINTS]
 * [DecodeFormatManager.DEFAULT_HINTS]
 *
 * 如果不满足您也可以通过[DecodeFormatManager.createDecodeHints]自己配置支持的格式
 * >
 * 识别区域可设置的方式有如下几种：
 * [.setFullAreaScan] 设置是否支持全区域扫码识别，优先级比识别区域高
 * [.setAnalyzeAreaRect] 设置需要分析识别区域，优先级比识别区域比例高，当设置了指定的分析区域时，识别区域比例和识别区域偏移量相关参数都将无效
 * [.setAreaRectRatio] 设置识别区域比例，默认[.DEFAULT_AREA_RECT_RATIO]，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别，优先级最低
 *
 *
 * 因为[androidx.camera.view.PreviewView]的预览区域是经过裁剪的，所以这里的区域并不是用户所能预览到的区域，而是指Camera预览的真实区域，
 *
 *
 * 即判定区域分析的优先级顺序为:[.setFullAreaScan] -> [.setAnalyzeAreaRect] -> [.setAreaRectRatio]
 *
 * >
 */
data class DecodeConfig(
    /**
     * 设置解码
     * 内置的一些解码可参见如下：
     * [DecodeFormatManager.DEFAULT_HINTS]
     * [DecodeFormatManager.ALL_HINTS]
     * [DecodeFormatManager.CODE_128_HINTS]
     * [DecodeFormatManager.QR_CODE_HINTS]
     * [DecodeFormatManager.ONE_DIMENSIONAL_HINTS]
     * [DecodeFormatManager.TWO_DIMENSIONAL_HINTS]
     * [DecodeFormatManager.DEFAULT_HINTS]
     * 如果不满足您也可以通过[DecodeFormatManager.createDecodeHints]自己配置支持的格式
     */
    var hints: MutableMap<DecodeHintType, Any> = DecodeFormatManager.DEFAULT_HINTS,
    /**
     * 是否支持使用多解码
     */
    val isMultiDecode: Boolean = true,
    /**
     * 是否支持识别反色码（条码黑白颜色反转的码）使用多解码
     * 默认为`false`，想要增强支持扫码识别反色码时可使用，相应的也会增加性能消耗。
     */
    val isSupportLuminanceInvertMultiDecode: Boolean = false,
    /**
     * 是否支持垂直的条码
     * 默认为`false`，想要增强支持扫码识别垂直的条码时可使用，相应的也会增加性能消耗。
     */
    val isSupportVerticalCode: Boolean = false,
    /**
     * 是否支持识别反色码（条码黑白颜色反转的码）
     * 默认为`false`，想要增强支持扫码识别反色码时可使用，相应的也会增加性能消耗。
     */
    val isSupportLuminanceInvert: Boolean = false,
    /**
     * 是否支持垂直的条码，使用多解码
     * 默认为`false`，想要增强支持扫码识别垂直的条码时可使用，相应的也会增加性能消耗。
     */
    val isSupportVerticalCodeMultiDecode: Boolean = false,
    //是否解析多个码
    val isMultipleCode: Boolean = false,
    /**
     * 设置需要分析识别区域，优先级比识别区域比例高，当设置了指定的分析区域时，识别区域比例和识别区域偏移量相关参数都将无效
     * @param analyzeAreaRect 识别区域可设置的方式有如下几种：
     * [.setFullAreaScan] 设置是否支持全区域扫码识别，优先级比识别区域高
     * [.setAnalyzeAreaRect] 设置需要分析识别区域，优先级比识别区域比例高，当设置了指定的分析区域时，识别区域比例和识别区域偏移量相关参数都将无效
     * [.setAreaRectRatio] 设置识别区域比例，默认[.DEFAULT_AREA_RECT_RATIO]，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别，优先级最低
     * 因为[androidx.camera.view.PreviewView]的预览区域是经过裁剪的，所以这里的区域并不是用户所能预览到的区域，而是指Camera预览的真实区域，
     * 即判定区域分析的优先级顺序为:[.setFullAreaScan] -> [.setAnalyzeAreaRect] -> [.setAreaRectRatio]
     */
    val analyzeAreaRect: Rect? = null,
    /**
     * 设置是否支持全区域扫码识别，优先级比识别区域高
     * @param fullAreaScan 默认为`true`
     * 识别区域可设置的方式有如下几种：
     * [.setFullAreaScan] 设置是否支持全区域扫码识别，优先级比识别区域高
     * [.setAnalyzeAreaRect] 设置需要分析识别区域，优先级比识别区域比例高，当设置了指定的分析区域时，识别区域比例和识别区域偏移量相关参数都将无效
     * [.setAreaRectRatio] 设置识别区域比例，默认[.DEFAULT_AREA_RECT_RATIO]，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别，优先级最低
     * 因为[androidx.camera.view.PreviewView]的预览区域是经过裁剪的，所以这里的区域并不是用户所能预览到的区域，而是指Camera预览的真实区域，
     * 即判定区域分析的优先级顺序为:[.setFullAreaScan] -> [.setAnalyzeAreaRect] -> [.setAreaRectRatio]
     */
    val isFullAreaScan: Boolean = false,
    /**
     * 默认0.8,，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
     * 设置识别区域比例，默认[.DEFAULT_AREA_RECT_RATIO]，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别，优先级最低
     *
     * @param areaRectRatio 识别区域可设置的方式有如下几种：
     * [.setFullAreaScan] 设置是否支持全区域扫码识别，优先级比识别区域高
     * [.setAnalyzeAreaRect] 设置需要分析识别区域，优先级比识别区域比例高，当设置了指定的分析区域时，识别区域比例和识别区域偏移量相关参数都将无效
     * [.setAreaRectRatio] 设置识别区域比例，默认[.DEFAULT_AREA_RECT_RATIO]，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别，优先级最低
     * 因为[androidx.camera.view.PreviewView]的预览区域是经过裁剪的，所以这里的区域并不是用户所能预览到的区域，而是指Camera预览的真实区域，
     * 即判定区域分析的优先级顺序为:[.setFullAreaScan] -> [.setAnalyzeAreaRect] -> [.setAreaRectRatio]
     */
    val areaRectRatio: Float = DEFAULT_AREA_RECT_RATIO,
    //识别区域垂直方向偏移量,支持负数，大于0时，居中心向下偏移，小于0时，居中心向上偏移
    val areaRectVerticalOffset: Int = 0,
    //识别区域水平方向偏移量,识别区域水平方向偏移量，支持负数，大于0时，居中心向右偏移，小于0时，居中心向左偏移
    val areaRectHorizontalOffset: Int = 0,
) {
    /**
     * 计算扫码区域
     */
    fun calculateScanningArea(width: Int, height: Int): Rect {
        if (isFullAreaScan) {
            // mDecodeConfig为空或者支持全区域扫码识别时，直接使用全区域进行扫码识别
            return Rect(0, 0, width, height)
        }
        val rect = analyzeAreaRect
        // 如果分析区域不为空，则使用指定的区域进行扫码识别
        if (rect != null) {
            return rect
        }
        // 如果分析区域为空，则通过识别区域比例和相关的偏移量计算出最终的区域进行扫码识别
        val size = (min(width, height) * areaRectRatio).toInt()
        val left = (width - size) / 2 + areaRectHorizontalOffset
        val top = (height - size) / 2 + areaRectVerticalOffset
        return Rect(left, top, left + size, top + size)
    }

    fun setHintsJava(hints: MutableMap<DecodeHintType, Any>): DecodeConfig {
        this.hints = hints
        return this
    }

    companion object {
        const val DEFAULT_AREA_RECT_RATIO = 0.8f
    }
}
